package com.bn.feed.scheduler;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.bn.feeds.MasterFeedConfiguration;
import com.bn.feeds.processor.MasterFeedsProcessor;
import com.bn.feeds.processor.ProductCategorizer;
import com.bn.feeds.tools.TruWorkFlowTools;

import atg.adapter.gsa.GSARepository;
import atg.nucleus.ServiceMap;
import atg.repository.ItemDescriptorImpl;
import atg.repository.Repository;
import atg.service.scheduler.ScheduledJob;
import atg.service.scheduler.Scheduler;
import atg.service.scheduler.SingletonSchedulableService;
import atg.servlet.ServletUtil;
import atg.userprofiling.email.MessageContentProcessor;
import atg.userprofiling.email.TemplateEmailException;
import atg.userprofiling.email.TemplateEmailInfoImpl;
import atg.userprofiling.email.TemplateEmailSender;

/**
 * The Class DailyFeedScheduler.
 * @author Parveen
 */
public class DailyFeedScheduler extends SingletonSchedulableService {

    /** The master feed processor. */
    private MasterFeedsProcessor masterFeedProcessor;
    
    /** The feeds to process. */
    private List<String> feedsToProcess;
    
    /** The feed congiuration map. */
    private ServiceMap feedCongiurationMap;
    
    private ProductCategorizer productCategorizer;
    
    /** The enabled. */
    private boolean enabled = true;
    
    private boolean checkSanityEnabled;
    
    /** The send email. */
    private boolean sendEmail = true;
    
    /** The delay bet feed millis. */
    private int delayBetFeedMillis = -1;
    
    /** The template email info. */
    private TemplateEmailInfoImpl templateEmailInfo;
    
    /** The template email sender. */
    private TemplateEmailSender templateEmailSender;
    
    private Repository productCatalog;
    private Repository versionManagerRepository;
    private Repository publishingRepository;

    /* (non-Javadoc)
     * @see atg.service.scheduler.SingletonSchedulableService#doScheduledTask(atg.service.scheduler.Scheduler, atg.service.scheduler.ScheduledJob)
     */
    @Override
    public void doScheduledTask(Scheduler arg0, ScheduledJob arg1) {
        if (isEnabled()) {
            processFeed();
            if(feedsToProcess.contains("Product")){
            	getProductCategorizer().process();	
            }
        }
    }

    /**
	 * Process feed.
	 */
    public void processFeed() {
    	
    	 Map<String, String> feedsOutput = new HashMap<String, String>();
         StringBuilder feedCompleteOutput = new StringBuilder();
         if(getMasterFeedProcessor().getFeedTools().getWorkFlowTools() instanceof TruWorkFlowTools && checkSanityEnabled){
         	TruWorkFlowTools workFlowTools = (TruWorkFlowTools) getMasterFeedProcessor().getFeedTools().getWorkFlowTools();
         	String message = workFlowTools.checkSanityTargets();
             if(message!=null){
             	feedCompleteOutput.append(message);
             	vlogError("BCC is not ready to accept the feed process due: {0}", message);
             	 try {
                     sendCompleteEmail(feedsOutput);
                 } catch (TemplateEmailException e) {
                     if(isLoggingError()){
                         logError("Error occured while sending email"+e.getMessage());
                     }
                 }
             	return ;
             }
             /*invalidateCache(getProductCatalog());
             invalidateCache(getVersionManagerRepository());
             invalidateCache(getPublishingRepository());*/
         }
    	
        if ((feedCongiurationMap == null) || (feedCongiurationMap.isEmpty())) {
            if (isLoggingDebug()) {
                logDebug("No configurations provided for Processing. Exiting.");
            }
            return;
        }
       
        for (String feedName : getFeedsToProcess()) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    		Calendar cal = Calendar.getInstance();
    		
    		StringBuilder feedOutput = new StringBuilder("<div id=\"feed\"> <h1>Start Feed Name : ").append(feedName).append("</h1> <br/> ");
    		feedOutput.append("<br>Feed Process Start time::").append(dateFormat.format(cal.getTime()));
            if (feedCongiurationMap.get(feedName) != null) {

                MasterFeedConfiguration config = (MasterFeedConfiguration) feedCongiurationMap.get(feedName);
                if (config.isEnable()) {
                    if (isLoggingInfo()) {
                        logInfo("STARTED: Proccessing for feed -- " + feedName);
                    }
                    getMasterFeedProcessor().processMasterFeedFile(config, feedOutput, feedName);
                    if (isLoggingInfo()) {
                        logInfo("ENDED: Proccessing for feed -- " + feedName);
                    }
                } else {
                    feedOutput.append(" <div id=\"error\">Feed is Disabled. Not Processing Feed.</div></div>");
                    
                    if (isLoggingInfo()) {
                        logInfo("EXITING : " + feedName + " is diabled ");
                    }
                }

            } else {
                feedOutput.append(" <div id=\"error\">No configuration found for the feed. Not Processing Feed.</div></div>");
            }
            
            //feedsOutput.put(feedName, feedOutput.toString());
            feedOutput.append("<br>Feed Process End time::").append(dateFormat.format(cal.getTime()));
            feedCompleteOutput.append(feedOutput);
            
            if (isLoggingInfo()) {
                logInfo("EXITING : " + feedName);
            }
            if (delayBetFeedMillis > -1){
                try {
                    Thread.sleep(delayBetFeedMillis);
                } catch (InterruptedException e) {
                    if (isLoggingError()){
                        logError("Error Occurred while trying to pause current thread for (time in milliseconds) : " + delayBetFeedMillis);
                    }
                }
            }
        }
        feedsOutput.put("message", feedCompleteOutput.toString());
        if (isLoggingDebug()){
            logDebug("FInal out put from feeds : " + feedsOutput);
        }
        try {
            sendCompleteEmail(feedsOutput);
        } catch (TemplateEmailException e) {
            if(isLoggingError()){
                logError("Error occured while sending email"+e.getMessage());
            }
            //e.printStackTrace();
        }
    }
    
    /**
	 * Send complete email.
	 * 
	 * @param feedsOutput
	 *            the feeds output
	 */
    private void sendCompleteEmail(Map<String, String> feedsOutput) throws TemplateEmailException{

        if (isSendEmail()){
            
            TemplateEmailInfoImpl templateInfo =getTemplateEmailInfo();
            MessageContentProcessor contentProcessor = templateInfo.getContentProcessor();
            String subject = templateInfo.getMessageSubject();
            String emailFrom = templateInfo.getMessageFrom();
            String templateURL =templateInfo.getTemplateURL();
            HashMap<String, Object> templateParams = new HashMap<String, Object>();
            templateParams.put("feedsOutput", feedsOutput.get("message"));
            templateParams.put("locale", ServletUtil.getCurrentRequest().getLocale());
            templateInfo.setTemplateURL(templateURL);
            templateInfo.setMessageFrom(emailFrom);
            templateInfo.setMessageSubject(subject);
            templateInfo.setTemplateParameters(templateParams);
            templateInfo.setContentProcessor(contentProcessor);
            ArrayList<String> emails = new ArrayList<String>();
            if (templateInfo.getMessageTo() != null) {
                emails.add(templateInfo.getMessageTo());
                if (isLoggingDebug()) logDebug("ArrayList<String> emails=....." + emails);
                try {
                    getTemplateEmailSender().sendEmailMessage(templateInfo, emails);
                }
                catch (TemplateEmailException e) {
                    if (isLoggingError()){
                        logError("Error Occurred while Sending emails " , e);
                    }
                } catch (Exception e) {
                    if (isLoggingError()){
                        logError("Error Occurred while Sending emails " , e);
                    }
                }
            }
        }
    }

    private void invalidateCache(Repository repository) {
    	if(null==repository)
    		return;
    	
        try {
            if (repository instanceof GSARepository) {
                // if we have a GSARepository type repository, type cast and call the invalidateCaches() method;
                ((GSARepository) repository).invalidateCaches();
            } else {
                String[] descriptorNames = repository.getItemDescriptorNames();

                // iterate over all the descriptors
                for (int i = 0; i < descriptorNames.length; i++) {
                    String descname = descriptorNames[i];
                    if (isLoggingDebug())
                        logDebug("Item Descriptor is : " + descname);
                    ItemDescriptorImpl itemdesc = (ItemDescriptorImpl) (repository.getItemDescriptor(descname));
                    itemdesc.invalidateCaches();
                }
            }
        } catch (Exception ex) {
            if (isLoggingError())
                logError("Exception occured while invalidating catalog repository", ex);
        }
    }
    /**
	 * Gets the master feed processor.
	 * 
	 * @return the master feed processor
	 */
    public MasterFeedsProcessor getMasterFeedProcessor() {
        return masterFeedProcessor;
    }

    /**
	 * Sets the master feed processor.
	 * 
	 * @param masterFeedProcessor
	 *            the new master feed processor
	 */
    public void setMasterFeedProcessor(MasterFeedsProcessor masterFeedProcessor) {
        this.masterFeedProcessor = masterFeedProcessor;
    }

    /**
	 * Checks if is enabled.
	 * 
	 * @return true, if is enabled
	 */
    public boolean isEnabled() {
        return enabled;
    }

    /**
	 * Sets the enabled.
	 * 
	 * @param enabled
	 *            the new enabled
	 */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
	 * Gets the feeds to process.
	 * 
	 * @return the feeds to process
	 */
    public List<String> getFeedsToProcess() {
        return feedsToProcess;
    }

    /**
	 * Sets the feeds to process.
	 * 
	 * @param feedsToProcess
	 *            the new feeds to process
	 */
    public void setFeedsToProcess(List<String> feedsToProcess) {
        this.feedsToProcess = feedsToProcess;
    }

    /**
	 * Gets the feed congiuration map.
	 * 
	 * @return the feed congiuration map
	 */
    public ServiceMap getFeedCongiurationMap() {
        return feedCongiurationMap;
    }

    /**
	 * Sets the feed congiuration map.
	 * 
	 * @param feedCongiurationMap
	 *            the new feed congiuration map
	 */
    public void setFeedCongiurationMap(ServiceMap feedCongiurationMap) {
        this.feedCongiurationMap = feedCongiurationMap;
    }

    /**
	 * Checks if is send email.
	 * 
	 * @return true, if is send email
	 */
    public boolean isSendEmail() {
        return sendEmail;
    }

    /**
	 * Sets the send email.
	 * 
	 * @param sendEmail
	 *            the new send email
	 */
    public void setSendEmail(boolean sendEmail) {
        this.sendEmail = sendEmail;
    }

    /**
	 * Gets the delay bet feed millis.
	 * 
	 * @return the delay bet feed millis
	 */
    public int getDelayBetFeedMillis() {
        return delayBetFeedMillis;
    }

    /**
	 * Sets the delay bet feed millis.
	 * 
	 * @param delayBetFeedMillis
	 *            the new delay bet feed millis
	 */
    public void setDelayBetFeedMillis(int delayBetFeedMillis) {
        this.delayBetFeedMillis = delayBetFeedMillis;
    }

    /**
	 * Gets the template email info.
	 * 
	 * @return the template email info
	 */
    public TemplateEmailInfoImpl getTemplateEmailInfo() {
        return templateEmailInfo;
    }

    /**
	 * Sets the template email info.
	 * 
	 * @param templateEmailInfo
	 *            the new template email info
	 */
    public void setTemplateEmailInfo(TemplateEmailInfoImpl templateEmailInfo) {
        this.templateEmailInfo = templateEmailInfo;
    }

    /**
	 * Gets the template email sender.
	 * 
	 * @return the template email sender
	 */
    public TemplateEmailSender getTemplateEmailSender() {
        return templateEmailSender;
    }

    /**
	 * Sets the template email sender.
	 * 
	 * @param templateEmailSender
	 *            the new template email sender
	 */
    public void setTemplateEmailSender(TemplateEmailSender templateEmailSender) {
        this.templateEmailSender = templateEmailSender;
    }

	public ProductCategorizer getProductCategorizer() {
		return productCategorizer;
	}

	public void setProductCategorizer(ProductCategorizer productCategorizer) {
		this.productCategorizer = productCategorizer;
	}

	public boolean isCheckSanityEnabled() {
		return checkSanityEnabled;
	}

	public void setCheckSanityEnabled(boolean checkSanityEnabled) {
		this.checkSanityEnabled = checkSanityEnabled;
	}

	public Repository getProductCatalog() {
		return productCatalog;
	}

	public void setProductCatalog(Repository productCatalog) {
		this.productCatalog = productCatalog;
	}

	public Repository getVersionManagerRepository() {
		return versionManagerRepository;
	}

	public void setVersionManagerRepository(Repository versionManagerRepository) {
		this.versionManagerRepository = versionManagerRepository;
	}

	public Repository getPublishingRepository() {
		return publishingRepository;
	}

	public void setPublishingRepository(Repository publishingRepository) {
		this.publishingRepository = publishingRepository;
	}

}
